/*
 *
 *  *
 *  *   Copyright 2020-2021 Luter.me
 *  *
 *  *   Licensed under the Apache License, Version 2.0 (the "License");
 *  *   you may not use this file except in compliance with the License.
 *  *   You may obtain a copy of the License at
 *  *
 *  *   http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *   Unless required by applicable law or agreed to in writing, software
 *  *   distributed under the License is distributed on an "AS IS" BASIS,
 *  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *   See the License for the specific language governing permissions and
 *  *   limitations under the License.
 *  *
 *
 */

package com.luter.heimdall.webflux.filter;

import com.luter.heimdall.webflux.web.WebFluxContextThreadLocalUtil;
import org.slf4j.Logger;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * request 和 response
 * <p>
 * 每次请求前，将 request 和 response 放入 ThreadLocal 中
 * <p>
 * 请求完毕，进入doFinally后，清理 ThreadLocal
 * <p>
 * 顺序：@Order(Ordered.HIGHEST_PRECEDENCE)
 *
 * @author luter
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ServerHttpRequestContextFilter implements WebFilter {
    /**
     * The constant log.
     */
    private static final transient Logger log = getLogger(ServerHttpRequestContextFilter.class);

    @Override
    public @NonNull
    Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        log.debug("[filter] Set Request and response Context: RequestId = [{}]", request.getId());
        WebFluxContextThreadLocalUtil.setRequest(request);
        WebFluxContextThreadLocalUtil.setResponse(response);
        return chain.filter(exchange).doFinally(r -> {
            log.debug("[filter]doFinally Clear all Context. SignalType = [{}], RequestId: = [{}]", r.name(), request.getId());
            WebFluxContextThreadLocalUtil.remove();
        });
    }
}
